package com.ymx.darling.spring.exception;

import com.ymx.darling.exception.DarlingException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.transaction.TransactionException;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.function.Supplier;

/**
 * 处理异常翻译
 * @author 爱Java的小于
 */
public class DarlingPersistenceExceptionTranslator implements PersistenceExceptionTranslator {
    private final Supplier<SQLExceptionTranslator> exceptionTranslatorSupplier;
    private SQLExceptionTranslator exceptionTranslator;

    public DarlingPersistenceExceptionTranslator(DataSource dataSource, boolean exceptionTranslatorLazyInit) {
        this(() -> new SQLErrorCodeSQLExceptionTranslator(dataSource), exceptionTranslatorLazyInit);
    }

    public DarlingPersistenceExceptionTranslator(Supplier<SQLExceptionTranslator> exceptionTranslatorSupplier, boolean exceptionTranslatorLazyInit) {
        this.exceptionTranslatorSupplier = exceptionTranslatorSupplier;
        if (!exceptionTranslatorLazyInit) {
            this.initExceptionTranslator();
        }

    }

    /**
     * 翻译异常
     * @param exception exception
     * @return DataAccessException
     */
    public DataAccessException translateExceptionIfPossible(RuntimeException exception) {
        if (exception instanceof DarlingException) {
            if (exception.getCause() instanceof SQLException) {
                this.initExceptionTranslator();
                String task = (exception).getMessage() + "\n";
                SQLException se = (SQLException)exception.getCause();
                DataAccessException dae = this.exceptionTranslator.translate(task, null, se);
                return (dae != null ? dae : new UncategorizedSQLException(task, null, se));

            } else if (exception.getCause() instanceof TransactionException) {
                throw (TransactionException) exception.getCause();

            } else {
                return new DarlingSystemException(exception.getMessage(), exception.getCause());
            }
        } else {
            return null;
        }
    }

    private synchronized void initExceptionTranslator() {
        if (this.exceptionTranslator == null) {
            this.exceptionTranslator = this.exceptionTranslatorSupplier.get();
        }
    }
}
